----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 			sneha nidhi
-- 
-- Create Date:    01:13:18 01/21/2011 
-- Design Name: 
-- Module Name:    MAIN_CONTROL - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
USE IEEE.numeric_std.all;
USE work.LCSE.all;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity MAIN_CONTROL is
	Port ( Reset 		: in  STD_LOGIC;
           Clk   		: in  STD_LOGIC;
           --------ROM---------------------------------------
			  ROM_Data 	: in  STD_LOGIC_VECTOR (11 downto 0); --Instruction,data bus program memory
           ROM_Addr 	: out  STD_LOGIC_VECTOR (11 downto 0);--Program_counter, written by main control--address bus program memory
           -----RAM------------------------------------------
			  RAM_Addr 	: out  STD_LOGIC_vector(7 downto 0);--written by main control--adress bus of data memory
			  RAM_CS   	: out  STD_LOGIC;--by main control
           RAM_Write : out  STD_LOGIC;--written by main control
           RAM_OE 	: out  STD_LOGIC;--written by main control
           -------DMA------------------------------------
			  Databus 	: inout  STD_LOGIC_vector(7 downto 0);
           DMA_RQ  	: in  STD_LOGIC;--from the DMA controler
           DMA_ACK 	: out  STD_LOGIC;--from by main control to dma
           SEND_comm : out  STD_LOGIC;--from by main control--transmission of data 
           DMA_READY : in  STD_LOGIC;--from the DMA controller
           -------ALU----------------------------------
			  u_instruction : out alu_op;-- to the alu
			  Index	   : in std_logic_vector(7 downto 0);
			  FlagZ     : in  STD_LOGIC;
			  FlagC     : in  STD_LOGIC;
           FlagN     : in  STD_LOGIC;
           FlagE     : in  STD_LOGIC
			  );

end MAIN_CONTROL;

architecture Behav of MAIN_CONTROL is

--------Internal Signals---------------------------------------------

type state is 			(idle, bus_cont, second_word, fetch, decode, exrd_ram, exwr_ram );

signal c_s, n_s		:state;  --current state , next state

signal ROM_Addr_s 	:STD_LOGIC_VECTOR (11 downto 0);--written by main control--address bus program memory--ROM_Addr
signal RAM_Addr_s 	:STD_LOGIC_vector(7 downto 0);--wr by main control--adress bus of data memory--RAM_Addr
signal DMA_ACK_s 		:STD_LOGIC;--written by main control--DMA_ACK
signal SEND_comm_s 	:STD_LOGIC;--written by main control--SEND_comm
signal Databus_int 	:STD_LOGIC_vector(7 downto 0);
signal alu_op_s		: alu_op;--temporary variable to store the operator value--u_instruction
signal Databus_OE    :STD_LOGIC;

------internal registers---------------
signal inst_reg		:STD_LOGIC_VECTOR (11 downto 0);--instruction register from rom_data
--signal pc				:STD_LOGIC_VECTOR (11 downto 0);--program counter--rom adress--mc

signal second_word_en:boolean;--load the second byte

----------------------------------------------------------------------
signal pc_flag       :STD_LOGIC;
signal inc_pc 			:STD_LOGIC;
signal jmp_pc			:STD_LOGIC_VECTOR (11 downto 0);
--signal pc_p1			:STD_LOGIC_VECTOR (11 downto 0);
signal pc_n			:STD_LOGIC_VECTOR (11 downto 0):=(others=>'0');
signal wr_decode		:STD_LOGIC;
signal RAM_Addr_oe	:STD_LOGIC;
--signal rst_pc		   :STD_LOGIC;
-----------------------------------------------------------------------
begin

process(reset,c_s,FlagZ,FlagC,FlagN,FlagE,DMA_RQ,DMA_READY,Index,ROM_Data,alu_op_s,pc_n,inc_pc,inst_reg,SEND_comm_s,ROM_Addr_s)
		
		begin
			
			---initial assignments---
			ROM_Addr_s<= (others => '0') after 1 ns;
			RAM_Addr_s<= (others => '0') after 1 ns;--RAM_Addr
			databus_int<= (others => '0') after 1 ns;
			RAM_CS <= '0' after 1 ns;
			DMA_ACK_s<='0' after 1 ns;--DMA_ACK
			
			second_word_en<= false after 1 ns;--load the second byte
			
			alu_op_s<= nop after 1 ns;
			RAM_OE<='0' after 1 ns;
			RAM_Write<='0' after 1 ns;
			Databus_OE<='0' after 1 ns;
			RAM_Addr_oe<='0' after 1 ns;
			
			pc_flag<='0' after 1 ns;
			inc_pc<='0' after 1 ns;
			jmp_pc<=(others => '0') after 1 ns;
			--pc_p1<=(others => '0') after 1 ns;
			--rst_pc<='0' after 1 ns;
			--pc<=(others => '0');
			n_s <= c_s after 1 ns;
			
	if (Reset='0') then
		n_s <= idle after 1 ns;
		alu_op_s<=nop after 1 ns;
		--pc<=(others => '0');
	else
		
		jmp_pc <= ROM_Data after 1 ns;
		
		case c_s is

		when idle =>--check id dma is requesting for the bus
		
			if (DMA_RQ='1') then --either so send or rx data
				n_s<=bus_cont after 1 ns;
			else 
				n_s<=fetch;--get the inst from the memory 
--				rst_pc<='1'after 1 ns;
--				n_s <= rst_pc_s after 1 ns;--get the inst from the memory 
			end if;	
---------------------------------------------------------------------------------------------------------------			
--		when rst_pc_s =>
--				if(rst_pc='1') then
--					pc<=(others => '0') after 1 ns;
--					n_s<=fetch after 1 ns;
--				elsif((inc_pc='1') and (DMA_RQ='0')and(DMA_READY='0'))then 
--					pc_p1 <= pc +'1' after 1 ns;
--					n_s<=fetch after 1 ns;
--				elsif ((DMA_RQ='1')or (DMA_READY='1')) then --either so send or rx data
--					n_s<=bus_cont after 1 ns;	
--				end if;	
--------------------------------------------------------------------------------------------------------------		
		when bus_cont =>--dma controller
		
			if((DMA_RQ='1')and not(inst_reg =  X"0" & TYPE_4 & "000000" ))then--dma rx the data
				
				DMA_ACK_s<='1' after 1 ns;--dma is rx the data
				RAM_OE<='0' after 1 ns;
				RAM_Write<='1' after 1 ns;
				n_s<= bus_cont after 1 ns;
				
			elsif((DMA_READY='1')and(inst_reg =  X"0" & TYPE_4 & "000000" ))then --tx the data
				
				SEND_comm_s<='1' after 1 ns;--giv order to the dma to tx the data stored in memory location
				DMA_ACK_s<='0' after 1 ns;
				RAM_OE<='1' after 1 ns;
				RAM_Write<='0' after 1 ns;
				n_s<= fetch after 1 ns;
			end if;
				
--///////////////////////////////////////////////////////////////////////////////////////////////////	

		when fetch =>
				ROM_Addr_s <= pc_n;
				if(second_word_en= true) then --flag to check if 2nd word is needed
					n_s<= second_word after 1 ns; 
				else 
					wr_decode<='1' after 1 ns;
					n_s<= decode after 1 ns;
				end if;
--///////////////////////////////////////////////////////////////////////////////////////////////////

		when decode =>
			
			
			if(inst_reg(11 downto 8) = "0000") then
				--type 1 instruction--1 byte
				
				if (inst_reg(7 downto 6) = TYPE_1) then
					--decide the opcode for the instructions
					if (DMA_RQ='1') then --either so send or rx data
						n_s<=bus_cont after 1 ns;
					else 
						inc_pc<='1' after 1 ns;
						n_s <= fetch;
					end if;
					if(inst_reg(5 downto 0) = ALU_ADD) then
						alu_op_s <= op_add after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_SUB) then
						alu_op_s <= op_sub after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_SHIFTL) then
						alu_op_s <= op_shiftl after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_SHIFTR ) then
						alu_op_s <= op_shiftr after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_AND) then
						alu_op_s <= op_and after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_OR) then
						alu_op_s <= op_or after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_XOR) then
						alu_op_s <= op_xor after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_CMPE ) then
						alu_op_s <= op_cmpe after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_CMPG) then
						alu_op_s <= op_cmpg after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_CMPL) then
						alu_op_s <= op_cmpl after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_ASCII2BIN)then
						alu_op_s <= op_ascii2bin after 1 ns;
					elsif (inst_reg(5 downto 0) = ALU_BIN2ASCII)then
						alu_op_s <= op_bin2ascii after 1 ns;
					end if;
					
					--n_s <= idle after 1 ns;

					--n_s <= rst_pc_s after 1 ns;

----------------------------------------------------------------------                       
				-- instruction type 2			
					
				elsif(inst_reg(7 downto 6) = TYPE_2) then
					if ((inst_reg(5 downto 0) = JMP_UNCOND)or(inst_reg(5 downto 0) = JMP_COND))then --jump inst
						inc_pc<='1' after 1 ns;
						n_s <= fetch after 1 ns;--it requires two bytes to call
	     				second_word_en<= true after 1 ns;
--					else 
--						n_s <= idle;
				 	end if;									
------------------------------------------------------------------------
				-- instruction type 3--1 byte
				
				elsif(inst_reg(7 downto 6) = TYPE_3) then
		
																-- instruction LD byte size is 1--register to register transfer
					if (inst_reg(5) = LD)then				--load instruction
																	--instruction of type byte size =1	   
						if(inst_reg(4 downto 0) = SRC_ACC & DST_A)then
							alu_op_s <= op_mvacc2a after 1 ns; --internal load registr from LCSE
							if (DMA_RQ='1')or(DMA_READY = '1') then --either so send or rx data
								n_s<=bus_cont after 1 ns;
							else 
								inc_pc<='1' after 1 ns;
								n_s <=fetch;
							end if;
							--n_s <= idle;
							--n_s <= rst_pc_s after 1 ns;
						elsif(inst_reg(4 downto 0) = SRC_ACC & DST_B)then
							alu_op_s <= op_mvacc2b after 1 ns;--internal load registr from LCSE
							if (DMA_RQ='1')or(DMA_READY = '1') then --either so send or rx data
								n_s<=bus_cont after 1 ns;
							else 
								inc_pc<='1' after 1 ns;
								n_s <= fetch;
							end if;
							--n_s <= idle;
							--n_s <= rst_pc_s after 1 ns;
						elsif(inst_reg(4 downto 0) = SRC_ACC & DST_INDX)then
							alu_op_s <= op_mvacc2id after 1 ns;--internal load registr from LCSE
							if (DMA_RQ='1')or(DMA_READY = '1') then --either so send or rx data
								n_s<=bus_cont after 1 ns;
							else 
								inc_pc<='1' after 1 ns;
								n_s <= fetch;
							end if;
							--n_s <= idle;
							--n_s <= rst_pc_s after 1 ns;
						else 
							inc_pc<='1' after 1 ns;
							n_s <=  fetch after 1 ns;--2 word inst
							second_word_en <= true after 1 ns;
						end if;

				--write instruction--2 byte cycles
					elsif(inst_reg(5) = WR )then
						if(inst_reg(4 downto 3) = SRC_ACC )then
							inc_pc<='1' after 1 ns;
							n_s <= fetch after 1 ns; --2nd word
	     					second_word_en <= true after 1 ns;
						elsif(inst_reg(4 downto 3) = SRC_CONSTANT)then
							inc_pc<='1' after 1 ns;
							n_s <= fetch after 1 ns;--2nd word
	     					second_word_en <= true after 1 ns;
--						else 
--							n_s <= idle;
						end if;
--					else 
--						n_s <= idle;
					end if;
----------------------------------------------------------------------------------------------------------------
				-- instruction type 4---tx the data to the rs232
				
				elsif(inst_reg(7 downto 6) = TYPE_4) then
					if(inst_reg(5 downto 0) = "000000") then --send comm signal tx  the data
						if(DMA_READY = '1') then--check is DMA free to transmit the data
							Send_comm_s <= '1' after 1 ns;-- if free then ready to tx the data
							n_s <= bus_cont after 1 ns;
							--n_s <= rst_pc_s after 1 ns;
						end if;
					end if;
--				else 
--					n_s <=idle;
				end if;
			end if;
--///////////////////////////////////////////////////////////////////////////////////////////////////
		
		when second_word =>
			if(inst_reg(7 downto 6) = TYPE_2) then
				
				if (DMA_RQ='1')or(DMA_READY = '1') then --either so send or rx data
					n_s<=bus_cont after 1 ns;
				else 
					inc_pc<='1' after 1 ns;
					n_s <= fetch;
				end if;
				--n_s <= idle after 1 ns;
				--n_s <= rst_pc_s after 1 ns;
				
				if(inst_reg(5 downto 0) = JMP_UNCOND) then
					pc_flag<='1' after 1 ns;
					
				elsif(inst_reg(5 downto 0) = JMP_COND) then
					if (FlagZ = '1')then
						pc_flag<='1' after 1 ns;
					end if;
				end if;

			elsif(inst_reg(7 downto 6) = TYPE_3)then
				if(inst_reg(5) = LD) then
						--load from a constant to a register
					if(inst_reg(4 downto 3) = SRC_CONSTANT) then
						Databus_OE <= '1' after 1 ns;
						Databus_int <= ROM_Data(7 downto 0);--load the data on the data bus
						
						if (DMA_RQ='1')or(DMA_READY = '1') then --either so send or rx data
							n_s<=bus_cont after 1 ns;
						else 
							inc_pc<='1' after 1 ns;
							n_s <=fetch;
						end if;
						
						--inc_pc<='1' after 1 ns;
						--n_s <= idle after 1 ns;
						--n_s <= rst_pc_s after 1 ns;
						if(inst_reg(2 downto 0) = DST_ACC) then
							alu_op_s <= op_ldacc;
						elsif(inst_reg(2 downto 0) = DST_A) then
							alu_op_s <= op_lda;	--external load operations
						elsif(inst_reg(2 downto 0) = DST_B) then
							alu_op_s <= op_ldb;--external load operations
						elsif(inst_reg(2 downto 0) = DST_INDX) then
							alu_op_s <= op_ldid;--external load operations
						end if;
							
		--load from memory to register--read from memory
					elsif(inst_reg(4 downto 3) = SRC_MEM)then  
						RAM_Addr_oe<='1' after 1 ns;
						RAM_Addr_s <= ROM_Data(7 downto 0) after 1 ns;
						n_s <= exrd_ram after 1 ns;
					elsif(inst_reg(4 downto 3) = SRC_INDXD_MEM)then  
						RAM_Addr_oe<='1' after 1 ns;
						RAM_Addr_s <= ROM_Data(7 downto 0) after 1 ns;
						n_s <= exrd_ram after 1 ns;
					end if;
		--execute write to the memory
				elsif(inst_reg(5) = WR)then
					if(inst_reg(2 downto 0) = DST_MEM)then
						n_s <= exwr_ram after 1 ns; 
					elsif(inst_reg(2 downto 0) = DST_INDXD_MEM)then
						n_s <= exwr_ram after 1 ns;
					end if;
				end if;
			end if;
--///////////////////////////////////////////////////////////////////////////////////////////////////		
		
		
		when  exrd_ram=>
			RAM_Write <= '0' after 1 ns;
			RAM_OE <= '1' after 1 ns;
			inc_pc<='1' after 1 ns;
			
			if (DMA_RQ='1')or(DMA_READY = '1') then --either so send or rx data
				n_s<=bus_cont after 1 ns;
			else 
				inc_pc<='1' after 1 ns;
				n_s <=fetch;
			end if;
			--n_s <= idle after 1 ns;
			--n_s<= rst_pc_s after 1 ns;
		--indexed  memory read
			if (inst_reg(4 downto 3) = SRC_INDXD_MEM)then  
				RAM_Addr_oe<='1' after 1 ns;
				RAM_Addr_s <= ROM_Data(7 downto 0) + Index after 1 ns;
			else 
				RAM_Addr_oe<='1' after 1 ns;
				RAM_Addr_s <= ROM_Data(7 downto 0) after 1 ns;--src memory read
			end if;
			
			if(inst_reg(2 downto 0) =DST_ACC)then
				alu_op_s <= op_ldacc after 1 ns;
			elsif(inst_reg(2 downto 0) = DST_A)then
				alu_op_s <= op_lda after 1 ns;	
			elsif(inst_reg(2 downto 0) = DST_B)then
				alu_op_s <= op_ldb after 1 ns;
			elsif(inst_reg(2 downto 0) = DST_INDX)then
				alu_op_s <= op_ldid after 1 ns;
--			else    
--				alu_op_s <= nop after 1 ns; 
--				n_s <=idle after 1 ns;  
			end if;
				
		
--///////////////////////////////////////////////////////////////////////////////////////////////////
		when exwr_ram=>
		
			RAM_Write <= '1' after 1 ns;
			RAM_OE <= '0' after 1 ns;
			alu_op_s <= op_oeacc after 1 ns;
			RAM_OE <= '1' after 1 ns;
			
			if (DMA_RQ='1')or(DMA_READY = '1') then --either so send or rx data
				n_s<=bus_cont after 1 ns;
			else 
				inc_pc<='1' after 1 ns;
				n_s <= fetch;
			end if;
			
			--inc_pc<='1' after 1 ns;
			if (inst_reg(2 downto 0) = DST_INDXD_MEM)then
				RAM_Addr_oe<='1' after 1 ns;
				RAM_Addr_s <= ROM_Data(7 downto 0) + Index after 1 ns;--indexed wr
			else 
				RAM_Addr_oe<='1' after 1 ns;
				RAM_Addr_s <= ROM_Data(7 downto 0) after 1 ns;--simple write
			end if;
				
		
	
----///////////////////////////////////////////////////////////////////////////////////////////////////	
		
		end case;
	end if;
	u_instruction<= alu_op_s after 1 ns;
	ROM_Addr<=ROM_Addr_s after 1 ns;
	SEND_comm<=SEND_comm_s after 1 ns;
	end process;
	


clking: process (Clk,reset) 
		begin
			if(reset='0') then
				pc_n<= (others=>'0') after 1 ns;
				c_s <= idle after 1 ns;
				DMA_ACK<='0'  after 1 ns;
				--pc<= (others=>'0') after 1 ns;
			elsif (Clk' event and Clk ='1') then	
				c_s <= n_s after 1 ns;
				DMA_ACK<=DMA_ACK_s after 1 ns;
				
				if(wr_decode='1')then
					inst_reg<= ROM_Data after 1 ns;					---instruction to be decoded
				end if;
				
				if(pc_flag='1')then						---jmp
					pc_n<=jmp_pc after 1 ns;
				elsif(inc_pc ='1') then					--increment the pointer
						pc_n <= (pc_n +'1') after 1 ns; --pc_p1
--					elsif(rst_pc='1') then
--						pc_n<= pc after 1 ns;
				end if;
			end if;
	end process clking;

  Databus <= Databus_int WHEN Databus_OE = '1' ELSE ("ZZZZZZZZ") after 1 ns;
  RAM_Addr<=RAM_Addr_s when RAM_Addr_oe='1' else ("ZZZZZZZZ") after 1 ns; 

end Behav;

